package com.ruoyi.taskasses;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.vo.CommonVO;
import com.ruoyi.common.exception.ProcessStopException;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ExecUtil;
import com.ruoyi.common.utils.SseEmitterUtils;
import com.ruoyi.common.utils.biz.BizModule;
import com.ruoyi.common.utils.biz.PathUtil;
import com.ruoyi.common.utils.biz.ResultSaveModule;
import com.ruoyi.dm.component.manager.TrackDataManager;
import com.ruoyi.dm.domain.po.CollectTleRecordPO;
import com.ruoyi.dm.domain.po.SpaceTargetMeasurePO;
import com.ruoyi.dm.service.ICollectTleRecordService;
import com.ruoyi.dm.service.ISpaceTargetMeasureService;
import com.ruoyi.dm.service.ISpaceTrackCollectRecordService;
import com.ruoyi.system.domain.ResultSave;
import com.ruoyi.system.service.IResultSaveService;
import com.ruoyi.system.service.ISysDictTypeService;
import com.ruoyi.taskasses.domain.*;
import com.ruoyi.trackapply.component.OriginNameFilter;
import com.ruoyi.trackapply.domain.CollectGnssPO;
import com.ruoyi.trackapply.domain.ForcastInputJsonBO;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Data
@Slf4j
public class OtherSpaceService {


    @Autowired
    PathUtil pathUtil;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TrackDataManager trackDataManager;

    @Autowired
    private ISpaceTrackCollectRecordService recordService;

    @Autowired
    private ICollectTleRecordService tleRecordService;

    private List<String> elements = ListUtil.of("X","Y","Z","VX","VY","VZ");

    //基础模型
    private List<String> baseModels = ListUtil.of("HADCAM",  "HALAM", "NRLMSISE-00", "Jacchia71", "JB2008", "DTM2020");

    @Autowired
    private ISpaceTargetMeasureService spaceTargetMeasureService;

    @Autowired
    private IResultSaveService resultSaveService;

    @Autowired
    private AllModeParamService allModeParamService;

    @Autowired
    private ISysDictTypeService dictTypeService;


    //tle数据预报
    public OtherSpaceReturnVO tleCal(AllModeParam param) throws Exception {
        //进度指示
        int percent = 1;
        SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");
        ForcastInputJsonBO forcastInputJsonBO = new ForcastInputJsonBO();
        ForcastInputJsonBO.InputBO inputBO = forcastInputJsonBO.new InputBO();
        forcastInputJsonBO.setInput(inputBO);
        inputBO.setTleFlag(true);
        inputBO.setIsGNSSpre(false);
        //时间
        DateTime startTime = DateTime.of(param.getStartTime());
        DateTime endTime = DateTime.of(param.getEndTime());

        //步骤一  找tle轨道数据,并写入 tle.txt
        LambdaQueryWrapper<CollectTleRecordPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CollectTleRecordPO::getTleCode,param.getObjectCode());
        //预报时间5天前的数据 取最近的数据
        //年纪日 格式  24023
        DateTime startDays = DateUtil.offset(startTime, DateField.DAY_OF_MONTH, -5);
        queryWrapper.between(CollectTleRecordPO::getDataTime,startDays,startTime);
        queryWrapper.orderByDesc(CollectTleRecordPO::getDataTime);
        queryWrapper.last(" limit 1");
        CollectTleRecordPO collectTleRecordPO = tleRecordService.getOne(queryWrapper);
        if (null == collectTleRecordPO) {
            throw new ServiceException(startTime +"前5天内 没有TLE数据 可供参考");
        }
        String tmpGnnsTxt = PathUtil.tmpModuleDir(BizModule.TASK_ASSESS) + "/" + UUID.fastUUID() + ".txt";
        File tleFile = FileUtil.writeString(collectTleRecordPO.toString(), tmpGnnsTxt, "utf-8");
        SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");
        inputBO.setTleFilePath(tleFile.getAbsolutePath());

        //组装预报时间
        ForcastInputJsonBO.StartTimeBO startBO = forcastInputJsonBO.new StartTimeBO();
        startBO.setBeginTime_Year(startTime.getField(DateField.YEAR));
        startBO.setBeginTime_Month(startTime.getField(DateField.MONTH)+1);
        startBO.setBeginTime_Day(startTime.getField(DateField.DAY_OF_MONTH));
        startBO.setBeginTime_Hour(startTime.getField(DateField.HOUR_OF_DAY));
        startBO.setBeginTime_Min(startTime.getField(DateField.MINUTE));
        startBO.setBeginTime_sec(Double.valueOf(startTime.getField(DateField.SECOND)));
        inputBO.setBeginTime(startBO);

        //预报结束时间
        ForcastInputJsonBO.EndTimeBO endBO = forcastInputJsonBO.new EndTimeBO();
        endBO.setEndTime_Year(endTime.getField(DateField.YEAR));
        endBO.setEndTime_Month(endTime.getField(DateField.MONTH)+1);
        endBO.setEndTime_Day(endTime.getField(DateField.DAY_OF_MONTH));
        endBO.setEndTime_Hour(endTime.getField(DateField.HOUR_OF_DAY));
        endBO.setEndTime_Min(endTime.getField(DateField.MINUTE));
        endBO.setEndTime_sec(Double.valueOf(endTime.getField(DateField.SECOND)));
        inputBO.setEndTime(endBO);
        //从数据库获取 查2个时间间隔  单位秒
        //int step = trackDataManager.queryStep(param.getSateName(), startTime, endTime);
        int step = 60;
        inputBO.setInterval(step);


        //一些配置
        ForcastInputJsonBO.ForcastConfBO confBO = forcastInputJsonBO.new ForcastConfBO();
        confBO.setDataPath("/dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/data/ADP/");
        confBO.setEphFilePath("/dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/data/ADP/JPLEPH.414");
        confBO.setStr("/dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/3rdparty/");
        forcastInputJsonBO.setConf(confBO);

        //遍历 每个模型 ，生成配置文件
        String tmpPath = UUID.randomUUID().toString();
        List<String> jsonPaths = new ArrayList<>();
        for (String model : baseModels) {
            //步骤二组装  ForcastInputJsonBO参数
            ForcastInputJsonBO.ForcastOutputBO bo = forcastInputJsonBO.new ForcastOutputBO();
            String outPath = PathUtil.outputModuleDir(BizModule.TASK_ASSESS) + "/other/";
            FileUtil.mkdir(outPath);
            bo.setFilePath(outPath+model+"_");
            forcastInputJsonBO.setOutput(bo);

            ForcastInputJsonBO.ForceModelParaBO forceModelParaBO = forcastInputJsonBO.new ForceModelParaBO();
            if (StringUtils.hasLength(param.getWindModel())) {
                switch (param.getWindModel()) {
                    case "HWM07":
                        forceModelParaBO.setWindFieldModel(1);
                        break;
                    case "HWCM":
                        forceModelParaBO.setWindFieldModel(2);
                        break;
                    default:
                        forceModelParaBO.setWindFieldModel(0);
                }
            }

            forceModelParaBO.setAtmDensityModel(checkModel(model));
            //forceModelParaBO.setAtmDensityModel(Integer.valueOf(model));
            inputBO.setForceModelPara(forceModelParaBO);

            //步骤三  写入入参
            String satJson = com.alibaba.fastjson.JSONObject.toJSONString(forcastInputJsonBO, new OriginNameFilter());
            String prettyStr = JSONUtil.toJsonPrettyStr(satJson);
            String inoutJsonPath = PathUtil.tmpModuleDir(BizModule.TASK_ASSESS) + "/"+tmpPath +"/"+ model+ "_InputOrbitPrediction.json";
            FileUtil.writeString(prettyStr,inoutJsonPath,"utf-8");
            jsonPaths.add(inoutJsonPath);
        }
        SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");
        //步骤四  调用脚本
        OtherSpaceInputJsonBO otherSpaceInputJsonBO = new OtherSpaceInputJsonBO();
        otherSpaceInputJsonBO.setSolar_value_max(param.getSunMax());
        otherSpaceInputJsonBO.setSolar_value_min(param.getSunMin());
        otherSpaceInputJsonBO.setAp_value_min(param.getGroundMin());
        otherSpaceInputJsonBO.setAp_value_max(param.getGroundMax());
        otherSpaceInputJsonBO.setEval_model(CollectionUtil.join(param.getModel(),","));
        otherSpaceInputJsonBO.setExe_input_json(jsonPaths);
        otherSpaceInputJsonBO.setSavePath(PathUtil.tmpModuleDir(BizModule.TASK_ASSESS));
        String paramJson = JSONUtil.toJsonStr(otherSpaceInputJsonBO);
        log.info("执行参数:{}",paramJson);
        String inoutJsonPath = PathUtil.tmpModuleDir(BizModule.TASK_ASSESS) + "/"+tmpPath +"/"+ "Deep_space_detection.json";
        FileUtil.writeString(paramJson,inoutJsonPath,"utf-8");
        String res = exec(inoutJsonPath, param.getSseId());
        String[] splitRes = res.split("\n");
        //log.info("调用预报命令 res-{}",res);
        //--10%
        //！！！！文件保存成功！！！！
        //###/dgdq/tmp/taskAssess/deep_space_detection_1721448327.txt###
        String resFile = "";
        for (String re : splitRes) {
            if (re.startsWith("###")) {
                String[] split = re.split("###");
                resFile = split[1];
            }
        }
        if ("".equals(resFile)) {
            throw new ServiceException("算法执行异常");
        }
        redisTemplate.opsForValue().set(MD5.create().digestHex(param.toString()),resFile,1, TimeUnit.HOURS);
        String resJson = FileUtil.readString(resFile, Charset.forName("utf-8"));
        OtherSpaceResBO resBO = JSONUtil.toBean(resJson, OtherSpaceResBO.class);
        SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");
        return dealWithReturn(resBO);

    }


    //精密轨道数据预报
    //基于配置文件的,所以每次只能串行
    public OtherSpaceReturnVO gnnsCal(AllModeParam param) throws Exception {
        //进度指示
        int percent = 1;
        SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");
        ForcastInputJsonBO forcastInputJsonBO = new ForcastInputJsonBO();
        ForcastInputJsonBO.InputBO inputBO = forcastInputJsonBO.new InputBO();
        forcastInputJsonBO.setInput(inputBO);
        inputBO.setTleFlag(false);
        inputBO.setIsGNSSpre(true);


        //时间
        DateTime startTime = DateTime.of(param.getStartTime());
        DateTime endTime = DateTime.of(param.getEndTime());

        //步骤一  找轨道原始数据,并写入 gnns.txt
        //update@2024-10-25 修改,避免不同星数据格式不一致
        DateTime end = DateUtil.endOfDay(startTime);
        List<CollectGnssPO> examplePOS = trackDataManager.queryGnns(param.getType(),param.getSateName(),startTime,end);
        if (CollectionUtil.isEmpty(examplePOS)) {
            throw new ServiceException(startTime+" 时间  GNSS无数据");
        }
        String exampleTxt = PathUtil.tmpModuleDir(BizModule.TRACK_APPLY) + "/" + UUID.fastUUID().toString(true) + ".txt";
        File orainFile = FileUtil.appendLines(examplePOS, exampleTxt, "utf-8");
        inputBO.setGnssFilePath(orainFile.getAbsolutePath());


        //组装预报时间
        DateTime forcastStart = new DateTime(examplePOS.get(0).getObs_time());
        ForcastInputJsonBO.StartTimeBO startBO = forcastInputJsonBO.new StartTimeBO();
        startBO.setBeginTime_Year(forcastStart.getField(DateField.YEAR));
        startBO.setBeginTime_Month(forcastStart.getField(DateField.MONTH)+1);
        startBO.setBeginTime_Day(forcastStart.getField(DateField.DAY_OF_MONTH));
        startBO.setBeginTime_Hour(forcastStart.getField(DateField.HOUR_OF_DAY));
        startBO.setBeginTime_Min(forcastStart.getField(DateField.MINUTE));
        startBO.setBeginTime_sec(Double.valueOf(forcastStart.getField(DateField.SECOND)));
        inputBO.setBeginTime(startBO);

        //预报结束时间
        DateTime forcastEnd = new DateTime(examplePOS.get(examplePOS.size()-1).getObs_time());
        ForcastInputJsonBO.EndTimeBO endBO = forcastInputJsonBO.new EndTimeBO();
        endBO.setEndTime_Year(forcastEnd.getField(DateField.YEAR));
        endBO.setEndTime_Month(forcastEnd.getField(DateField.MONTH)+1);
        endBO.setEndTime_Day(forcastEnd.getField(DateField.DAY_OF_MONTH));
        endBO.setEndTime_Hour(forcastEnd.getField(DateField.HOUR_OF_DAY));
        endBO.setEndTime_Min(forcastEnd.getField(DateField.MINUTE));
        endBO.setEndTime_sec(Double.valueOf(forcastEnd.getField(DateField.SECOND)));
        inputBO.setEndTime(endBO);
        //从数据库获取 查2个时间间隔  单位秒
        int step = trackDataManager.queryStep(examplePOS);
        inputBO.setInterval(step);

        //查询 目标信息，备用
        LambdaQueryWrapper<SpaceTargetMeasurePO> measureQw = new LambdaQueryWrapper<>();
        measureQw.select(SpaceTargetMeasurePO::getCode,SpaceTargetMeasurePO::getName,SpaceTargetMeasurePO::getDens,SpaceTargetMeasurePO::getWindArea,SpaceTargetMeasurePO::getFIndex,SpaceTargetMeasurePO::getLightIndex);
        measureQw.eq(SpaceTargetMeasurePO::getName,param.getSateName());
        SpaceTargetMeasurePO measure = spaceTargetMeasureService.getOne(measureQw);
        if (null == measure) {
            throw new ServiceException("未找到 "+param.getSateName()+" 的目标测量数据,请先去目标测量页面增加数据!");
        }

        //一些配置
        ForcastInputJsonBO.ForcastConfBO confBO = forcastInputJsonBO.new ForcastConfBO();
        confBO.setDataPath("/dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/data/ADP/");
        confBO.setEphFilePath("/dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/data/ADP/JPLEPH.414");
        confBO.setStr("/dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/3rdparty/");
        forcastInputJsonBO.setConf(confBO);

        SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");

        //评估结果
        //遍历 每个模型 ，生成配置文件
        String tmpPath = UUID.randomUUID().toString();
        List<String> jsonPaths = new ArrayList<>(baseModels.size());
        for (String model : baseModels) {
            //修改输出
            //输出
            ForcastInputJsonBO.ForcastOutputBO bo = forcastInputJsonBO.new ForcastOutputBO();
            String outPath = PathUtil.outputModuleDir(BizModule.TASK_ASSESS) + "/other/";
            FileUtil.mkdir(outPath);
            bo.setFilePath(outPath+model+"_");
            forcastInputJsonBO.setOutput(bo);

            //步骤二组装  ForcastInputJsonBO参数
            ForcastInputJsonBO.ForceModelParaBO forceModelParaBO = forcastInputJsonBO.new ForceModelParaBO();
            forceModelParaBO.setDragCd(Double.valueOf(measure.getFIndex()));
            forceModelParaBO.setDragArea(Double.valueOf(measure.getWindArea()));
            forceModelParaBO.setDragMass(Double.valueOf(measure.getDens()));
            forceModelParaBO.setCr(Double.valueOf(measure.getLightIndex()));
            forceModelParaBO.setAtmDensityModel(checkModel(model));
            if (StringUtils.hasLength(param.getWindModel())) {
                switch (param.getWindModel()) {
                    case "HWM07":
                        forceModelParaBO.setWindFieldModel(1);
                        break;
                    case "HWCM":
                        forceModelParaBO.setWindFieldModel(2);
                        break;
                    default:
                        forceModelParaBO.setWindFieldModel(0);
                }
            }
            inputBO.setForceModelPara(forceModelParaBO);

            //步骤三  写入入参
            String satJson = com.alibaba.fastjson.JSONObject.toJSONString(forcastInputJsonBO, new OriginNameFilter());
            String prettyStr = JSONUtil.toJsonPrettyStr(satJson);
            String inoutJsonPath = PathUtil.tmpModuleDir(BizModule.TASK_ASSESS) + "/"+tmpPath +"/"+ model+ "_InputOrbitPrediction.json";
            FileUtil.writeString(prettyStr,inoutJsonPath,"utf-8");
            jsonPaths.add(inoutJsonPath);
        }
        SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");
        //步骤四  调用脚本
        OtherSpaceInputJsonBO otherSpaceInputJsonBO = new OtherSpaceInputJsonBO();
        otherSpaceInputJsonBO.setSolar_value_max(param.getSunMax());
        otherSpaceInputJsonBO.setSolar_value_min(param.getSunMin());
        otherSpaceInputJsonBO.setAp_value_min(param.getGroundMin());
        otherSpaceInputJsonBO.setAp_value_max(param.getGroundMax());
        otherSpaceInputJsonBO.setEval_model(CollectionUtil.join(param.getModel(),","));
        otherSpaceInputJsonBO.setExe_input_json(jsonPaths);
        otherSpaceInputJsonBO.setSavePath(PathUtil.tmpModuleDir(BizModule.TASK_ASSESS));
        String paramJson = JSONUtil.toJsonStr(otherSpaceInputJsonBO);
        log.info("执行参数:{}",paramJson);
        String inoutJsonPath = PathUtil.tmpModuleDir(BizModule.TASK_ASSESS) + "/"+tmpPath +"/"+ "Deep_space_detection.json";
        FileUtil.writeString(paramJson,inoutJsonPath,"utf-8");
        String res = exec(inoutJsonPath,param.getSseId());
        String[] splitRes = res.split("\n");
        log.info("执行命令结果:{}", JSONUtil.toJsonStr(splitRes));
        //--10%
        //！！！！文件保存成功！！！！
        //###/dgdq/tmp/taskAssess/deep_space_detection_1721448327.txt###
        String resFile = "";
        for (String re : splitRes) {
            if (re.startsWith("###")) {
                String[] split = re.split("###");
                resFile = split[1];
            }
        }
        if ("".equals(resFile)) {
            throw new ServiceException("算法执行异常");
        }
        redisTemplate.opsForValue().set(MD5.create().digestHex(param.toString()),resFile,1, TimeUnit.HOURS);
        String resJson = FileUtil.readString(resFile, Charset.forName("utf-8"));
        OtherSpaceResBO resBO = JSONUtil.toBean(resJson, OtherSpaceResBO.class);
        SseEmitterUtils.sendMessage(param.getSseId(),++percent+"0");
        return dealWithReturn(resBO);

    }

    //将数据抽稀
    private List thin(List xList) {
        //页面展示1000条数据
        //小于100 直接返回
        int size = xList.size();
        if (size<1000) {
            return xList;
        }
        int num = 1000;
        int skip = (int) (size / num);
        int lineNum = 0;
        List dataList = new ArrayList<>(1100);
        for (int i = 0; i < size; i++) {
            if (lineNum % skip == 0) {
                dataList.add(xList.get(i));
            }
            lineNum++;
        }
        return dataList;
    }

    /**
     * 通过模型 映射 数字
     * //1为STANDARY_1976,2为HARRIS_PRIESTER,3为JACCHIA_1970,4为JACCHIA_1971,5为NRLMSISE_2000，
     * // 6为MSISE_1990,7为MSISE_1986,8为JACCHIA_1960,9为JACCHIA_ROBERTS,10为CIRA_1972
     * @param model
     * @return
     */
    private int checkModel(String model) {
        switch (model) {
            case "HADCAM":return 1;
            case "HALAM":return 2;
            case "NRLMSISE-00":return 3;
            case "Jacchia71":return 4;
            case "JB2008":return 5;
            case "DTM2020":return 6;
            default: throw new ServiceException("无效的模型名称:"+model);
        }
    }


    //页面 返回特定的格式
    private OtherSpaceReturnVO dealWithReturn(OtherSpaceResBO bo) {
        OtherSpaceReturnVO resVO = new OtherSpaceReturnVO();
        List<String> models = new ArrayList<>();
        models.add("平均");
        //评估结果
        List<EstimateAnalysisResVO> estimates = new ArrayList<>();
        List<Map<String, OtherSpaceResBO.ErrorBo>> boErrorList = bo.getErrorList();
        for (Map<String, OtherSpaceResBO.ErrorBo> modelError : boErrorList) {
            for (Map.Entry<String, OtherSpaceResBO.ErrorBo> innerMap : modelError.entrySet()) {
                String model = innerMap.getKey();
                models.add(model);
                OtherSpaceResBO.ErrorBo value = innerMap.getValue();
                EstimateAnalysisResVO x = EstimateAnalysisResVO.builder().model(model).avg(new BigDecimal(value.getX_average()))
                        .rmse(new BigDecimal(value.getX_RMS())).
                        max(new BigDecimal(value.getX_max()) ).
                        min(new BigDecimal(value.getX_min()) ).dire("X").build();
                EstimateAnalysisResVO y = EstimateAnalysisResVO.builder().model(model)
                        .avg(new BigDecimal(value.getY_average()) )
                        .rmse(new BigDecimal(value.getY_RMS()) )
                        .max(new BigDecimal(value.getY_max()) )
                        .min(new BigDecimal(value.getY_min()) ).dire("Y").build();
                EstimateAnalysisResVO z = EstimateAnalysisResVO.builder().model(model)
                        .avg(new BigDecimal(value.getZ_average()) )
                        .rmse(new BigDecimal(value.getZ_RMS()) )
                        .max(new BigDecimal(value.getZ_max()) )
                        .min(new BigDecimal(value.getZ_min()) ).dire("Z").build();
                EstimateAnalysisResVO xyz = EstimateAnalysisResVO.builder().model(model)
                        .avg(new BigDecimal(value.getXYZ_average()) )
                        .rmse(new BigDecimal(value.getXYZ_RMS()) )
                        .max(new BigDecimal(value.getXYZ_max()) )
                        .min(new BigDecimal(value.getXYZ_min()) ).dire("XYZ").build();
                estimates.add(x);
                estimates.add(y);
                estimates.add(z);
                estimates.add(xyz);
            }
        }
        resVO.setModels(models);
        resVO.setEstimate(estimates);
        //太阳指数
        OtherSpaceReturnVO.IndexBO solarIndex = resVO.new IndexBO();
        solarIndex.setMax(bo.getSolar_value_max());
        solarIndex.setMin(bo.getSolar_value_min());
        solarIndex.setIndex(thin(bo.getSpaceIndexsData().getF107_index_data_list()));
        solarIndex.setIndexDate(thin(bo.getSpaceIndexsData().getF107_datetime_list()));
        resVO.setSolarIndex(solarIndex);

        //地磁
        OtherSpaceReturnVO.IndexBO geoIndex = resVO.new IndexBO();
        geoIndex.setMax(bo.getGeoma_index_max());
        geoIndex.setMin(bo.getGeoma_index_min());
        geoIndex.setIndex(thin(bo.getSpaceIndexsData().getAP_index_data_list()));
        geoIndex.setIndexDate(thin(bo.getSpaceIndexsData().getAP_datetime_list()));
        resVO.setGeoIndex(geoIndex);

        //时序分布
        OtherSpaceReturnVO.TimeResBO timeResBO = resVO.new TimeResBO();
        Map dataTime = bo.getDataTime();
        List<String> timeList = thin((List) dataTime.get("all_time"));
        List<Date> collect = timeList.stream().map(str -> {
            return DateUtil.parse(str,"yyyy-MM-dd HH:mm:ss");
        }).collect(Collectors.toList());
        timeResBO.setTime(collect);
        Set<String> set = dataTime.keySet();
        HashMap<String, List> innerXmap = new HashMap<>();
        HashMap<String, List> innerYmap = new HashMap<>();
        HashMap<String, List> innerZmap = new HashMap<>();
        for (String key : set) {
            if (key.endsWith("_X")) {
                innerXmap.put(key,thin((List)dataTime.get(key)));
            }else if (key.endsWith("_Y")) {
                innerYmap.put(key,thin((List)dataTime.get(key)));
            }if (key.endsWith("_Z")) {
                innerZmap.put(key,thin((List)dataTime.get(key)));
            }
        }
        timeResBO.setXres(innerXmap);
        timeResBO.setYres(innerYmap);
        timeResBO.setZres(innerZmap);
        resVO.setTimeRes(timeResBO);

        //判断哪个是最优模型
        EstimateAnalysisResVO bestVO = estimates.stream().min(Comparator.comparing(EstimateAnalysisResVO::getRmse)).get();
        resVO.setResult(String.format("所选时间范围内，最优模型为：%s",bestVO.getModel()));

        return resVO;
    }

    public void ybSave(AllModeParam param,String model,String subModel) {
        param.setStartTime(DateUtil.truncate(param.getStartTime(), DateField.DAY_OF_MONTH));
        param.setEndTime(DateUtil.truncate(param.getEndTime(), DateField.DAY_OF_MONTH));
        String res =(String) redisTemplate.opsForValue().get(MD5.create().digestHex(param.toString()));
        if (null == res) {
            throw new ServiceException("请先计算");
        }
        param.setSseId(null);

        ResultSave entity = ResultSave.builder()
                .params("")
                .module(model)
                .submodule(subModel)
                .resultData(JSONUtil.toJsonStr(ListUtil.of(res)))
                .startTime(DateUtil.format(param.getStartTime(),"yyyy-MM-dd"))
                .endTime(DateUtil.format(param.getEndTime(),"yyyy-MM-dd"))
                .createTime(new Date())
                .build();
        resultSaveService.resultSave(param,entity);
    }

    public void save(AllModeParam param) {
        String method = param.getMethod();
        String model = ResultSaveModule.TASK_ASSESS;
        String subModel = ResultSaveModule.TASK_ASSESS_OTHER;
        if ("dg".equals(method)) {
            allModeParamService.dgSave(param,model,subModel);
        }else if ("yb".equals(method)) {
            this.ybSave(param,model,subModel);
        }else {
        }
    }

    private File ybDownload(AllModeParam param) {
        param.setStartTime(DateUtil.truncate(param.getStartTime(), DateField.DAY_OF_MONTH));
        param.setEndTime(DateUtil.truncate(param.getEndTime(), DateField.DAY_OF_MONTH));
        String res =(String) redisTemplate.opsForValue().get(MD5.create().digestHex(param.toString()));
        if (null == res) {
            throw new ServiceException("请先计算");
        }
        return new File(res);
    }

    public File download(AllModeParam param) throws IOException {
        String method = param.getMethod();
        if (!StringUtils.hasLength(method)) {
            //兼容 ,默认是 定轨
            method="yb";
        }
        if ("dg".equals(method)) {
            return allModeParamService.download(param);
        }else if ("yb".equals(method)) {
            return this.ybDownload(param);
        }else {
            return null;
        }
    }


    public OtherSpaceReturnVO ybMethodcal(AllModeParam param) throws Exception {
        param.setStartTime(DateUtil.truncate(param.getStartTime(), DateField.DAY_OF_MONTH));
        param.setEndTime(DateUtil.truncate(param.getEndTime(), DateField.DAY_OF_MONTH));
        if ("track".equals(param.getFocastType())) {
            return gnnsCal(param);
        }else if ("tle".equals(param.getFocastType())) {
            return tleCal(param);
        }
        return null;
    }


    private String exec(String jsonPath, String sseId) throws ProcessStopException {
        String script = PathUtil.codeModuleDir(BizModule.TASK_ASSESS) + PathUtil.moduleDirs().getTaskAssess().get("otherSpace");

        String commond = String.format("cd /dgdq/code/dgdq-algorithm/taskAssess/orbitpredict/bin && python %s %s", script, jsonPath);
        List<String> strings = ExecUtil.execPythonZw(Stream.of("bash", "-c", commond).collect(Collectors.toList()), sseId);
        String join = CollectionUtil.join(strings, "\n");
        return join;

    }
    public OtherSpaceReturnVO cal(AllModeParam param) throws Exception {
        String method = param.getMethod();
        if (!StringUtils.hasLength(method)) {
            //兼容 ,默认是 定轨
            method="yb";
        }
        if ("dg".equals(method)) {
            return allModeParamService.dgMethod(param);
        }else if ("yb".equals(method)) {
            return this.ybMethodcal(param);
        }else {
            return null;
        }
    }

    /**
     * 通过不同 任务选取不同卫星
     * 交会对接 inter;在轨 on;目标陨落 fall
     * @param type
     * @return
     */
    public List<CommonVO> sateList(String type) {
        List<SysDictData> data = null;
        if ("inter".equals(type)) {
            data = dictTypeService.selectDictDataByType("station_list");
        }else if ("on".equals(type)) {
            data = dictTypeService.selectDictDataByType("tack_satellite");
        }else if ("fall".equals(type)) {
            data = dictTypeService.selectDictDataByType("fall_satellite_list");
        }
        if (null != data)  {
            List<CommonVO> voList = data.stream().map(dict -> {
                return new CommonVO(dict.getDictValue(), dict.getDictLabel());
            }).collect(Collectors.toList());
            return voList;
        }
        return null;
    }
}
